asynx.namespace("selector");

asynx.selector = function() {
	var xQuery = arguments[0], s = arguments[1];
	
	if (typeof xQuery == "object") {
		if (xQuery!=window && xQuery!=document)
			xQuery = this.increaseObj(xQuery);
		return xQuery;
	}
	
	this.init(xQuery, s);
	return this.nodes;
};

asynx.selector.prototype = {
	
	nodes: [],
	query: null,
	xQuery: null,
	
	init: function() {
		
		
		this.query = new String(arguments[0]).replace("*=", " all=");
		//alert(this.query)
		var matchers = [
			/^([\w-]+)\.([\w-]+)$/, //div.className
			/^([\w-]+)\.([\w-]+)\[([\w-]+)\]$/, //div.className[a]
			/^#(.*)$/, //#id
			/^([\w-]+)$/, //id
			/^([\w-]+) *[\/>] *([\w-]+)$/, //ul/li or ul>li
			/\]\[ *@([\w-]+) *(=|<|>|>=|<=|!=|\^=|\$=|all=)? *(['"]?([\w.-]+|)?['"]?)? *\]$/ //input[@type='radio'][@checked='3']
		];
		
		var rules = [
			{ tag:1, css:2 },
			{ tag:1, css:2, contains:3 },
			{ id: 1 },
			{ id: 1 },
			{ tag1: 1, tag2:2 },
			{ attr2:1, comparator:2, value2:4 }
		];
		
		var xAttr = "//{tag}[@{attr}='{value}']";
		
		var attrFilter, valueFilter, comparatorFilter;
		
		asynx.each(matchers, function(regex, x) {
			var m = this.query.match(regex);
			if (m) { 

				var tag = m[rules[x].tag];
				var tag1 = m[rules[x].tag1];
				var tag2 = m[rules[x].tag2];
				var css = m[rules[x].css];
				var id = m[rules[x].id];
				var contains = m[rules[x].contains];
				var attr2 = m[rules[x].attr2];
				var attrFilter = attr2;
				var value2 = m[rules[x].value2];
				var valueFilter = value2;
				var comparator = m[rules[x].comparator];
				var comparatorFilter = comparator;
				
				var byId = !!(id);
				var byTagCss = !!(tag && css);
				var byTagCssContains = !!(tag && css && contains);
				var byChildren = !!(tag1 && tag2);
				var bySecondAttr = !!(attr2 && !value2);
				var bySecondAttrValue = !!(attr2 && value2);
				
				if (byId) 
					this.xQuery = xAttr.replace("{attr}", "id").
						replace("{value}", id).replace("{tag}", "");
				
				if (byTagCss) {
					this.xQuery = xAttr.replace("{attr}", "class").
						replace("{value}", css).replace("{tag}", tag);
				}
				if (byTagCssContains)
					this.xQuery = xAttr.replace("{attr}", "class").
						replace("{value}", css).replace("{tag}", tag)+"["+contains+"]";
				
				if (byChildren)
					this.xQuery = "//"+tag1+"//"+tag2;
					
				if (bySecondAttr || bySecondAttrValue) {
					this.xQuery = this.query.replace(regex, "]");
				}
			//	alert(tag + "-" + css + "-" + id + "-" +  attr2 +"-" +  value2 + "=" + this.xQuery)
			};
		}, this);
		
		if (!this.xQuery) 
			this.xQuery = this.query;
		
		this.nodes = this.getNodes(arguments[1]);
		
		if (attrFilter && comparatorFilter)
			this.nodes = asynx.xpath.filter(this.nodes, attrFilter, valueFilter, {comparator:comparatorFilter, customSelector:undefined});
		
		if (this.nodes.length == 1) {
			// ie bug
			var anodes = asynx.extend({},this.nodes);
			this.nodes = asynx.isXMLDoc(anodes[0]) ? [anodes[0]] : anodes[0];
		}
		
		
		this.nodes = this.increaseObj(this.nodes);
	},
	
	getNodes: function() {
		return asynx.xpath.getNodes(this.xQuery, arguments[0]);
	},
	
	increaseObj: function(element) {
		
		element.each = function(fn) {
			asynx.each(this, function(e,x) {
				if (this) fn.apply(this, [e, x]);
			}, arguments[1]);
		};
		
		element.click = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.click(element, fn, args[1]);
			return element;
		};
		
		element.dblclick = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.dblclick(element, fn, args[1]);
			return element;
		};
		
		element.onblur = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.blur(element, fn, args[1]);
			return element;
		};
		
		element.onchange = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.change(element, fn, args[1]);
			return element;
		};
		
		element.onfocus = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.focus(element, fn, args[1]);
			return element;
		};
		
		element.load = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.load(element, fn, args[1]);
			return element;
		};
		
		element.keypress = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.keypress(element, fn, args[1]);
			return element;
		};
		
		element.keyup = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.keyup(element, fn, args[1]);
			return element;
		};
		
		element.keydown = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.keydown(element, fn, args[1]);
			return element;
		};
		
		element.mouseover = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.mouseover(element, fn, args[1]);
			return element;	
		};
		
		element.mouseout = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.mouseout(element, fn, args[1]);
			return element;
		};
		
		element.mousedown = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.mousedown(element, fn, args[1]);
			return element;
		};
		
		element.mouseup = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.mouseup(element, fn, args[1]);
			return element;
		};
		
		element.mousemove = function(fn) {
			var args = asynx.A(arguments);
			asynx.event.mousemove(element, fn, args[1]);
			return element;
		};
		
		element.whileKeyPressed = function(keys) {
			var fn = arguments[1];
			var fargs = arguments[2];
			var fnEnd = arguments[3];
			var fargsEnd = arguments[4];
			var scope = arguments[5];
			
			element.each(function(node){
				asynx.event.whileKeyPressed(node, keys, fn, fargs, fnEnd, fargsEnd, scope);	
			}, this);
			return element;
		};
		
		element.onStopTyping = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.onStopTyping(node, fn, args[1], args[2]);	
			}, this);
			return element;
		};
		
		element.html = function(html) {
			var evals = arguments[1];
			asynx.html(element, html, evals);
			return element;
		};
		
		element.appendHtml = function(h) {
			element.html(element.innerHTML+h, arguments[1]);
			return element;
		};
		
		element.openUrl = function(url) {
			var args = asynx.A(arguments);
			var url = args[0];
			var data = args[1];
			var fn = args[2];
			var fnArgs = args[3];

			asynx.$open(url, data, function(r,a) {
				element.each(function(node){
					element.html(r);
					if (fn) fn.apply(node, [r, fnArgs]);
				}, this);
			});
			return element;
		};
		
		element.css = function(s) {
			var args = asynx.A(arguments);
			var values = [];
			
			element.each(function(node){
				var v = asynx.css(node, s);
				if (!asynx.isUndef(v)) values.push(v);
			}, this);
			
			return values.length==1?values[0]:values;
		};
		
		element.splash = function() {
			asynx.anim.splash(element, arguments[0], arguments[1], arguments[2]);
			return element;
		};
		
		element.splashElastic = function() {
			asynx.anim.splashElastic(element, arguments[0], arguments[1], arguments[2]);
			return element;
		};
		
		return element;
	}
	
};
